▶️ Video Guide: Building with GraphRAG
When RAG (and GraphRAG) first entered the scene, everyone was creating their own custom implementations for pulling data from an external source to provide as context to an LLM. As usage increased, frameworks began to incorporate abstracted, out-of-the-box approaches to handle retrieval augmented generation.
For those early adopters of GraphRAG, however, these initial offerings still required significant customization to add further context from a graph retrieval query. Things have improved greatly since then, and Spring AI offers a couple of ready-to-use options through their Advisors API.
Neo4j graph database and the data
A Neo4j graph database is already set up, populated, and running in the cloud with public data. Anyone is welcome to connect to the database and explore.
The data set contains Goodreads book, review, author, and user information, and has already been designed for Generative AI with embeddings for book and review text (using an OpenAI text model).

Fig. 1: Goodreads graph data model
Our solution will provide users with book recommendations tailored to specific search criteria. Semantic search through vector embeddings enables us to search based on narrower criteria, such as “step-by-step to improve motivation” or “stories with bravery and medieval elements like King Arthur”.
Note: The stored data is tailored to Spring AI’s use of the generic Document entity, so some fields on the Book and Review nodes are duplicated as metadata.< property >.
Spring AI advisors
The Spring AI advisor API is designed to streamline interactions between LLMs and applications by building reusable components that allow developers to switch underlying components, such as models and vector stores.
There are two advisor approaches Spring offers out of the box, but developers can also create their own custom implementations.
- Question Answer Advisor: A starter advisor for vector search, requires a vector store parameter.
- Retrieval Augmentation Advisor: Part of a library of modules to create RAG pipelines with modular components, requires a separate dependency.
This post will show both default and custom advisors for GraphRAG. All of the code for today is available in a Github repository. Feel free to follow along or clone and run the repository yourself!

Fig. 2: GraphRAG architecture
Project setup
The configuration parameters for this application are already set in the src/main/resources/application.properties file. To run the project, you will need to set your OpenAI API key as an environment variable or set the corresponding property in this file.
There are two beans for Neo4j vector stores defined in the SpringAiRagAdvisorsApplication.java. These are necessary for later join retrieval, combining results from two separate vector searches. One bean looks for a vector index on Review-labeled nodes, and the other looks for a vector index on Book-labeled nodes.
Domain entity
Although Spring uses a general Document entity to map results from a vector store, I have found that LLMs handle the recommendations better when they are returned as Book entities. The Book.java maps the general entity’s fields to a Book object, and any nested/relevant fields are mapped to the metadata variable (properties in the database must have a prefix of_`metadata._ to get picked up).
[source,java]
—-
public record Book(@Id String id,
String text,
Map<String, Object> metadata) {
}
—-
Controller class
The controller class is where the application accepts incoming requests, processes them, and responds accordingly. All the logic for this is contained in the RAGController.java class.
To start, the injected ChatClient handles interactions with the Large Language Model (OpenAI, here). Both Neo4j vector store beans (vectorStoreReviews and vectorStoreBooks) also get injected, and then we add the GraphRetrievalAdvisor custom advisor and the GraphQueryAugmenter class, which we will explain shortly. We also define a system prompt to guide any behavior the LLM should or shouldn’t use in the answer.
[source,java]
—-
@RestController
@RequestMapping("/")
public class RAGController {
private final ChatClient chatClient;
private final Neo4jVectorStore vectorStoreReviews;
private final Neo4jVectorStore vectorStoreBooks;
private final GraphRetrievalAdvisor graphRetrievalAdvisor;
private final GraphQueryAugmenter graphQueryAugmenter;
String prompt = """
You are a book expert providing recommendations based on the book reviews provided in the context.
Please summarize the books provided.
""";
//constructor
}
—-
QuestionAnswer advisor
Next, we add endpoints to utilize Spring AI advisors. Spring offers two main, out-of-the-box advisors – the QuestionAnswerAdvisor and the RetrievalAugmentationAdvisor. We will start with the QuestionAnswerAdvisor, which will execute a similarity search for the input.
[source,java]
—-
@GetMapping("/qa")
public String getQAAdvised(@RequestParam String query) {
return chatClient.prompt()
.system(prompt).user(query)
.advisors(new SimpleLoggerAdvisor(),
new QuestionAnswerAdvisor(vectorStoreReviews),
graphRetrievalAdvisor)
.call().content();
}
—-
This method maps to the /qa endpoint and requires a query parameter containing the search topic(s) the user is interested in for book recommendations. The method doesn’t have too much logic, calling the LLM with the system prompt defined earlier, adding advisors for logging (output to console) and the QuestionAnswerAdvisor to search the vector store. The final line executes that call and returns the content key from the response object, containing the answer string from the LLM.
While the QuestionAnswerAdvisor handles RAG, it only handles the vector search that finds book reviews with similar text to the user’s query. We also need a graph retrieval query to retrieve related information for book recommendations, such as book titles, ratings, and other relevant details. The GraphRetrievalAdvisor will pass the results from the QuestionAnswerAdvisor to the graph retrieval query, and update the context for the LLM.
Custom GraphRAG advisor
A custom advisor requires implementing the adviseCall(), getName(), and getOrder() methods. We also need to inject a repository interface that executes a graph query against Neo4j to pull the related entities for the similar documents.
[source,java]
—-
@Component
public class GraphRetrievalAdvisor implements CallAdvisor {
private final BookRepository repo;
public GraphRetrievalAdvisor(BookRepository repo) {
this.repo = repo;
}
//adviseCall method
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public int getOrder() {
return 1;
}
}
—-
The @Component annotation causes Spring to pick up this class as a bean and implement the CallAdvisor interface. Within the class, the BookRepository gets injected and added to the constructor. The advisor methods follow (annotated with @Override). The getName() method defines a name to reference the class, and the getOrder() method sets the order in which this advisor should be executed in a chain. Because the vector search should always be executed first, and the GraphRetrievalAdvisor should be called second, we set the index to 1.
Circling back, the core of the advisor logic is in the adviseCall() method.
[source,java]
—-
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
var documents = findDocumentsInContext(chatClientRequest.context());
//null and empty check
List<Book> bookList = repo.findBooks(
documents.stream().map(Document::getId).collect(Collectors.toList())
);
String bookContext = bookList.stream()
.map(Book::toString)
.collect(Collectors.joining("\n"));
SystemMessage systemMessage = new SystemMessage("Use these books for context: " + bookContext);
var updatedPrompt = new Prompt(List.of(chatClientRequest.prompt().getUserMessage(), systemMessage));
var updatedRequest = ChatClientRequest.builder()
.prompt(updatedPrompt)
.context(Map.of()) //Clear the context
.build();
System.out.println("----- Updated request -----");
System.out.println(updatedRequest);
return callAdvisorChain.nextCall(updatedRequest);
}
private List<Document> findDocumentsInContext(Map<String, Object> context) {
var documents = (List<Document>) context.get("qa_retrieved_documents");
if (documents == null || documents.isEmpty()) {
documents = (List<Document>) context.get("rag_document_context");
}
return documents;
}
—-
First, the findDocumentsInContext() method extracts the similarity search result documents from the QuestionAnswerAdvisor context, maps them to a documents variable, and checks whether they are null/empty. It retrieves documents from one of two keys in the context, because we use both the QuestionAnswerAdvisor and the RetrievalAugmentationAdviso` in this application.
The next code block calls the repository’s findBooks() method, passing in the IDs of the similar documents, and returns the results as Book entities. Then, the code adds the returned book string onto the prompt as another system message.
Finally, the updatedRequest variable modifies the ChatClientRequest object with the updated prompt and removes the previous context, reducing the overall message length and saving some tokens. The final line in the adviseCall() method closes this advisor, ending this application’s chain.
Testing the QuestionAnswerAdvisor
Let’s test the QuestionAnswerAdvisor and custom GraphRetrievalAdvisor using the /qa endpoint. Start the application, either via an IDE or at the command line with ./mvnw spring-boot:run. Then open a terminal window and send a request to the endpoint.
[source,shell]
—-
jenniferreif@elf-lord spring-ai-rag-advisors % http ":8080/qa?query=I want to challenge my mind and would like to read something about technology"
—-
The returned answer might look something like this (output has been trimmed):
[source,shell]
—-
Based on your interest in reading about technology, I recommend "Ada Byron Lovelace and the Thinking Machine." This nonfiction book explores the life of Ada Lovelace…
Another great option is "Our Molecular Future: How Nanotechnology, Robotics, Genetics and Artificial Intelligence Will Transform Our World." This book highlights emerging technologies and discusses their potential impact…
If you're looking for something more thrilling, "Game Changer" is an intellectual thriller that combines futuristic technology with an engaging storyline…
Let me know if you'd like more information on any of these titles!
—-
To verify these results, data is logged to the console for us to view the recommended books passed to the LLM. Fields have been trimmed for easier reading.
[source,shell]
—-
Book[id=24694140, text=Ada Lovelace, the daughter of the famous romantic poet, Lord Byron, develops her creativity through science and math..., metadata={average_rating=4.19, title=Ada Byron Lovelace and the Thinking Machine, reviews=[{rating=4, text=Read Harder Challenge 2017 #13 Read a nonfiction book about technology.}], url=https://www.goodreads.com/book/show/24694140-ada-byron-lovelace-and-the-thinking-machine}]
Book[id=30052254, text=...Kevin Quinn is a Secret Service agent who believes the president needs to die, and is determined to make this happen..., metadata={average_rating=4.21, title=Game Changer, reviews=[{rating=5, text=Intellectual thriller. I love a book that makes me think, imagine, and is still entertaining. Game Changer definitely fits that bill. While the technology seemed so futuristic, it didn't seem farfetched…}], url=https://www.goodreads.com/book/show/30052254-game-changer}]
Book[id=2264743, text=In this riveting thriller, 14-year-old Steven "Steel" Trapp sets off with his mom and their dog..., metadata={average_rating=3.85, title=The Challenge (Steel Trapp, #1), reviews=[{rating=1, text=The things I read to win challenges and pass tests surprise me…}], url=https://www.goodreads.com/book/show/2264743.The_Challenge}]
Book[id=664068, text=...What will happen to our jobs, health care, and investments when the molecular revolution hits? How might artificial intelligence transform..., metadata={average_rating=3.59, title=Our Molecular Future: How Nanotechnology, Robotics, Genetics and Artificial Intelligence Will Transform Our World, reviews=[{rating=4, text=Very interesting book highlighting up and coming technologies. Very readable.}], url=https://www.goodreads.com/book/show/664068.Our_Molecular_Future}]
—-
Notice that the LLM’s response dropped “The Challenge” from the list, but after reading the book and review text, we can see that it isn’t directly tied to challenging our minds or technology. This is where the LLM excels, evaluating results and summarizing key points.
Next, we will try out Spring’s more flexible Retrieval Augmentation Advisor.
Retrieval Augmentation Advisor
This advisor allows you to compose your own RAG pipeline from a series of flexible modules. Your ideal pipeline might include some pre-preprocessing, post-processing, or filtering functions to refine similarity search results, and this delivers. You can define/configure whichever modules you need in your pipeline and skip any you don’t.
To utilize these modules, the pom.xml file needs a separate dependency.
[source,xml]
—-
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
—-
The next couple of examples still need the custom GraphRetrievalAdvisor to add the graph context, but this article’s final example replaces that with an augmentor module!
Retrieval advisor
Back in the RAGController class, the getRAGAdvised() method uses the RetrievalAugmentationAdvisor.
[source,java]
—-
@GetMapping("/retrievalAdvisor")
public String getRAGAdvised(@RequestParam String query) {
Advisor retrievalAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStoreReviews)
.build())
.build();
return chatClient.prompt()
.system(prompt).user(query)
.advisors(new SimpleLoggerAdvisor(),
retrievalAdvisor,
graphRetrievalAdvisor)
.call().content();
}
—-
What’s different about the RAG modules is that we need to configure one or more for our specific pipeline. The getRAGAdvised() method configures an advisor object with a documentRetriever (vector store similarity search), then calls the chatClient chain with this retrievalAdvisor. Note that this method performs the same function as the QuestionAnswerAdvisor, which invokes a similarity search and the custom graph advisor.
Testing this endpoint and reviewing the console data yields the same results as the QuestionAnswerAdvisor, which is expected, since they execute the same functions. To take this a step further, let’s use some of the other RAG modules available, starting with filtering.
Filtering vector search results
Once we retrieve similar reviews, we might want to filter the results by rating, number of reviews, publisher, or another criterion. Adding a keyword search as a filter can be really powerful, but also requires some preparation, as the desired filter fields must be on the expected node in the graph and prefixed withmetadata.in the property name.
For our use case, we will find review ratings higher than 3 stars.
[source,java]
—-
@GetMapping("/retrieveFilter")
public String getRetrieveFilterAdvised(@RequestParam String query) {
Advisor ragRetrieveFilterAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStoreReviews)
.filterExpression(new FilterExpressionBuilder()
.gt("rating", 3)
.build())
.build())
.build();
return chatClient.prompt()
.system(prompt).user(query)
.advisors(new SimpleLoggerAdvisor(),
ragRetrieveFilterAdvisor,
graphRetrievalAdvisor)
.call().content();
}
—-
The advisor configures a document retriever, then appends a `filterExpression()` that looks for a `rating` property greater than (`.gt()`) a value of 3. We can see the difference in results by testing.
[source,java]
—-
jenniferreif@elf-lord spring-ai-rag-advisors % http ":8080/retrieveFilter?query=I am looking for a relaxing and easy read for a mountain vacation"
You might consider "The Last Juror" as it is described as excellent reading for a vacation or a day off, perfect for a little escapism.
—-
Console data (trimmed):
[source,java]
—-
Book[id=5346, text=In 1970, one of Mississippi's more colorful weekly newspapers, TheFord County Times,went bankrupt. To the surprise and dismay of many, ownership was assumed by a 23-year-old college dropout..., metadata={average_rating=3.86, title=The Last Juror, reviews=[{rating=4, text=Excellent reading for a vacation or a day off…}], url=https://www.goodreads.com/book/show/5346.The_Last_Juror}]
—-
Let’s compare this against the results from running the same input against the plain RAG advisor.
[source,shell]
—-
jenniferreif@elf-lord spring-ai-rag-advisors % http ":8080/retrievalAdvisor?query=I am looking for a relaxing and easy read for a mountain vacation"
#Console data (trimmed for brevity):
Book[id=20881071, metadata={average_rating=4.05, title=The Burning Room (Harry Bosch, #19; Harry Bosch Universe, #26), reviews=[{rating=0}]}]
Book[id=5346, metadata={average_rating=3.86, title=The Last Juror, reviews=[{rating=4}]}]
Book[id=3613997, metadata={average_rating=3.64, title=The Associate, reviews=[{rating=3}]}]
Book[id=11881678, metadata={average_rating=3.12, title=Dollhouse, reviews=[{rating=2}]}]
—-
Checking the ratings above, we can confirm that the filter worked, as it only returned “The Last Juror” as a recommendation (note that “The Associate” is rated a 3, not greater than).
Joining vector searches
Another module combines multiple vector searches (and different vector stores) into a single set of results. To do this, use the document join option.
[source,java]
—-
@GetMapping("/retrieveJoin")
public String getRetrievalJoinAdvised(@RequestParam String query) {
Advisor ragRetrieveJoinAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStoreReviews)
.build())
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStoreBooks)
.build())
.documentJoiner(new ConcatenationDocumentJoiner())
.build();
return chatClient.prompt()
.system(prompt).user(query)
.advisors(new SimpleLoggerAdvisor(),
ragRetrieveJoinAdvisor,
graphRetrievalAdvisor)
.call().content();
}
—-
Notice that there are two document retrievers attached to the advisor block – one for reviews and one for books. This is where the two separate Neo4jVectorStore beans are needed. This query performs similarity searches on Book nodes and Review nodes, and then combines the two sets.
[source,shell]
—-
jenniferreif@elf-lord spring-ai-rag-advisors % http ":8080/retrieveJoin?query=I'd like to read something about personal growth and small town living"
You might enjoy "Growing Up on the Edge of the World" by Phil Callaway. It is a tender coming-of-age story set in a small town in Canada…
Additionally, "Voices in the Hills: Collected Ramblings from a Rural Life" by Nessa Flax offers reflections on life in rural Vermont and New Hampshire…
Both of these books capture themes of personal growth and the richness of small-town life.
#Console context (trimmed):
Book[id=2371618, text=Award-winning columnist and author Phil Callaway offers up his first novel filled with the warmth and richness readers have come to love! This tender coming-of-age story is set on "the edge of the world"--a small town..., metadata={average_rating=3.94, title=Growing Up on the Edge of the World, reviews=[{rating=5, text=Loved this book & his other…}, {rating=3, text=Decent story set in a small town…}], url=https://www.goodreads.com/book/show/2371618.Growing_Up_on_the_Edge_of_the_World}]
Book[id=22792008, text="Travel invigorates and enlightens, and so does reading..., metadata={average_rating=4.58, title=Everywhere Stories: Short Fiction from a Small Planet, reviews=[{rating=5, text=I am the editor of this anthology, and I think it's awesome…}, {rating=5, text=Each story is set in a different place in the world…}, {rating=5, text=It's reassuring to learn…}], url=https://www.goodreads.com/book/show/22792008-everywhere-stories}]
Book[id=14476104, text=This is a book with all the color and rhythm of the seasons of New England..., metadata={average_rating=3.93, title=Voices in the Hills: Collected Ramblings from a Rural Life, reviews=[{rating=3, text=Sensitive treatment of that age-old question, 'Can you ever go home again?'....}, {rating=4, text=This book was won by me in the GoodReads Giveaway….}, {rating=4, text=...I found that when the pace of my life was feeling frenetic, reading a column of rural ramblings…}, {rating=5, text=Voices in the Hills are short reflections from her weekly column about rural Vermont living…}], url=https://www.goodreads.com/book/show/14476104-voices-in-the-hills}]
Book[id=30024726, text=The radical search for the simple life in today's America..., metadata={average_rating=3.84, title=The Unsettlers: In Search of the Good Life in Today's America, reviews=[{rating=3, text=This was an interesting look at different ways people in America are living…}, {rating=4, text=This book covered a lot of topics...}, {rating=3, text=Compelling subject matter but…}, {rating=4, text=This book spoke of the author's quest to find the simple life in today's America…}, {rating=4, text=...author Mark Sundeen immersed himself in the worlds of three different families of radical off-gridders…}, {rating=4, text=An important book…"}, {rating=5, text=I have been reading a lot of memoirs and how-to books about permaculture, small-scale farming, and homesteading…}, {rating=5, text=This is a book about people who are going against the cultural grain…}, {rating=4, text=The author interviewed three different couples about their living the simple life…}, {rating=5, text=Fun book, learned a lot about farming and back to earth working and relationships and people.}, {rating=3, text=I get what Sundeen is trying to do and I'm even impressed with…}, {rating=5, text=From the first few pages I was drawn to the story and the themes…}], url=https://www.goodreads.com/book/show/30024726-the-unsettlers}]
—-
You might notice that more reviews for each book are returned (the last two, especially). This is due to the vector search against books, as it is not limited by the number of reviews the query pulls for each resulting book.
Query augmentation
In this last example, we can replace the custom GraphRAG advisor with the ContextualQueryAugmenter.
[source,java]
—-
@GetMapping("/retrieveAugment")
public String getRetrievalAugmentAdvised(@RequestParam String query) {
Advisor retrieveAugmentAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStoreReviews)
.build())
.queryAugmenter(graphQueryAugmenter)
.build();
return chatClient.prompt()
.system(prompt).user(query)
.advisors(new SimpleLoggerAdvisor(),
retrieveAugmentAdvisor)
.call().content();
}
—-
However, we still need to customize the augmenter to execute a graph retrieval query, which is housed in the GraphQueryAugmenter class.
[source,java]
—-
@Component
public class GraphQueryAugmenter implements QueryAugmenter {
private final BookRepository bookRepository;
public GraphQueryAugmenter(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@Override
public Query augment(Query query, List<Document> documents) {
//null check
List<String> docIds = documents.stream()
.map(Document::getId)
.collect(Collectors.toList());
List<Book> books = bookRepository.findBooks(docIds);
if (books.isEmpty()) {
return query;
}
String bookContext = books.stream()
.map(Book::toString)
.collect(Collectors.joining("\n"));
String augmentedText = query.text() + "\n\nAdditional book context:\n" + bookContext;
return new Query(augmentedText);
}
}
—-
The class extends the query augmentor and injects the BookRepository to access the graph retrieval query. The augmentor also requires us to implement methods, but only for augment(). It accepts the similarity search documents, extracts the IDs from the documents into a list, and calls the graph retrieval query to find related books. The resulting list is formatted into a string (bookContext) and returned as a Query object.
Testing this endpoint shows the same results as our initial GraphRAG tests for /qa and /retrievalAdvisor. Text has been trimmed for this post.
[source,shell]
—-
jenniferreif@elf-lord spring-ai-rag-advisors % http ":8080/retrieveAugment?query=I want to challenge my mind and would like to read something about technology"
Here are four book recommendations related to technology that can challenge your mind:
1. **Ada Byron Lovelace and the Thinking Machine** by Laurie Wallmark and April Chu
- This nonfiction book tells the story of Ada Lovelace…
[Read more here](https://www.goodreads.com/book/show/24694140-ada-byron-lovelace-and-the-thinking-machine)
2. **Game Changer** by Douglas E. Richards
- A gripping thriller where Kevin Quinn, a Secret Service agent, believes that the president needs to die and takes drastic measures to make it happen. The book is praised for its intellectual depth and futuristic technology that feels plausible…
[Read more here](https://www.goodreads.com/book/show/30052254-game-changer)
3. **The Challenge (Steel Trapp, #1)** by Ridley Pearson
- This thrilling adventure follows 14-year-old Steven "Steel" Trapp as he embarks on a journey to compete in a National Science Competition…
[Read more here](https://www.goodreads.com/book/show/2264743.The_Challenge)
4. **Our Molecular Future: How Nanotechnology, Robotics, Genetics and Artificial Intelligence Will Transform Our World** by Douglas Mulhall
- This book discusses the upcoming molecular revolution and its implications for jobs, healthcare, and investments…
[Read more here](https://www.goodreads.com/book/show/664068.Our_Molecular_Future)
These selections should provide a variety of perspectives on technology, from historical accounts to thrilling fiction and forward-looking analyses.
—-
Console data (trimmed):
[source,shell]
—-
Book[id=24694140, text=Ada Lovelace, the daughter of the famous romantic poet, Lord Byron, develops her creativity through science and math..., metadata={average_rating=4.19, title=Ada Byron Lovelace and the Thinking Machine, reviews=[{rating=4, text=Read Harder Challenge 2017 #13 Read a nonfiction book about technology.}], url=https://www.goodreads.com/book/show/24694140-ada-byron-lovelace-and-the-thinking-machine, authors=[{name=Laurie Wallmark}, {name=April Chu}]}]
Book[id=30052254, text=...Kevin Quinn is a Secret Service agent who believes the president needs to die, and is determined to make this happen. But when Quinn becomes the most wanted man in Ame..., metadata={average_rating=4.21, title=Game Changer, reviews=[{rating=5, text=Intellectual thriller. I love a book that makes me think, imagine, and is still entertaining. Game Changer definitely fits that bill. While the technology seemed so futuristic, it didn't seem farfetched…}], url=https://www.goodreads.com/book/show/30052254-game-changer,authors=[{name=Douglas E. Richards}]}]
Book[id=2264743, text=In this riveting thriller, 14-year-old Steven "Steel" Trapp sets off with his mom and their dog, Cairo, on a 2-day Amtrak journey to compete in the National Science Competition..., metadata={average_rating=3.85, title=The Challenge (Steel Trapp, #1), reviews=[{rating=1, text=The things I read to win challenges and pass tests surprise me…}], url=https://www.goodreads.com/book/show/2264743.The_Challenge, authors=[{name=Ridley Pearson}]}]
Book[id=664068, text=...What will happen to our jobs, health care, and investments when the molecular revolution hits? How might artificial intelligence transform..., metadata={average_rating=3.59, title=Our Molecular Future: How Nanotechnology, Robotics, Genetics and Artificial Intelligence Will Transform Our World, reviews=[{rating=4, text=Very interesting book highlighting up and coming technologies. Very readable.}], url=https://www.goodreads.com/book/show/664068.Our_Molecular_Future, authors=[{name=Douglas Mulhall}]}]
—-
Reviewing the full console output reveals less context clutter and detailed results in the Query Augment approach. It produces a separate section for additional context, rather than adding another system message onto the thread with the updated context (as the GraphRetrievalAdvisor did).
Wrapping up
In this article, we explored Spring AI advisors for RAG. We started with the out-of-the-box QuestionAnswerAdvisor, but needed a custom GraphRetrievalAdvisor to handle the graph retrieval query piece of the GraphRAG. Next, we turned to RAG modules in the RetrievalAugmentationAdvisor for plain RAG, retrieval filtering, similarity search joins, and retrieval augmentation.
Next steps for this project could combine RAG modules for both query transformation and retrieval augmentation, or filtering and augmentation. No matter where you go next, Spring AI advisors offer straightforward paths for building powerful RAG solutions.
Happy coding!
Resources
Author
🔍 Frequently Asked Questions
1. What is GraphRAG and how does it differ from standard RAG?
GraphRAG extends standard RAG by combining vector similarity search with a graph database query, retrieving not just semantically similar documents but also their structured relationships — such as book titles, authors, and ratings linked to matching reviews. Standard RAG retrieves flat documents from a vector store; GraphRAG adds a second retrieval step that traverses graph edges to surface richer, more contextually accurate results. - In Spring AI, this second step is handled by a custom GraphRetrievalAdvisor or a GraphQueryAugmenter that queries Neo4j after the initial vector search. - GraphRAG is particularly effective when your data has meaningful relationships — e.g., reviews linked to books, books linked to authors — that a flat vector index cannot capture.
2. How does the Spring AI Advisor API work?
The Spring AI Advisor API wraps LLM interactions in reusable, chainable components called advisors, each responsible for a specific step — such as vector retrieval, logging, or context augmentation — executed in a defined order before the final call reaches the model. Advisors intercept the ChatClientRequest, modify the prompt or context, and pass control to the next advisor via CallAdvisorChain. - Spring provides two ready-to-use advisors: QuestionAnswerAdvisor (basic vector search) and RetrievalAugmentationAdvisor (modular RAG pipeline with filtering, joining, and augmentation). -Custom advisors implement the CallAdvisor interface and override adviseCall(), getName(), and getOrder().
3. Can I filter vector search results in Spring AI by metadata fields like rating?
Yes — Spring AI's VectorStoreDocumentRetriever supports metadata filtering via FilterExpressionBuilder, letting you restrict similarity search results to documents that match specific field conditions, such as returning only reviews with a rating greater than 3. The target field must exist on the node in the graph and be prefixed with metadata. in the property name. - Filtering is configured inline on the RetrievalAugmentationAdvisor builder — no separate post-processing step is required. - Supported operators include .gt(), .lt(), .eq(), and logical combinators, matching the standard Spring AI filter expression DSL.
4. What is the difference between QuestionAnswerAdvisor and RetrievalAugmentationAdvisor in Spring AI?
QuestionAnswerAdvisor is a single-step, zero-configuration advisor that runs a similarity search against one vector store; RetrievalAugmentationAdvisor is a composable pipeline builder that lets you chain multiple retrievers, apply metadata filters, join results from different vector stores, and plug in custom augmentors — all within one advisor declaration. - Use QuestionAnswerAdvisor when you need a quick RAG prototype with minimal setup. - Use RetrievalAugmentationAdvisor (requires the spring-ai-rag dependency) when your production pipeline needs filtering, multi-store joins, or query augmentation — such as appending graph context from Neo4j before the LLM call.




